Collection   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 123
dl 0
loc 172
rs 8.8798
c 0
b 0
f 0
wmc 44

19 Functions

Rating   Name   Duplication   Size   Complexity  
A first 0 3 3
A pluck 0 19 4
A merge 0 4 1
A random 0 3 1
A last 0 3 3
A whereBetween 0 5 1
A unique 0 8 2
A whereNotBetween 0 5 1
A whereNotIn 0 4 1
A whereNotNull 0 4 1
A toJSON 0 3 1
A whereNotInstanceOf 0 4 1
B _getRowFieldResult 0 22 8
A whereNull 0 5 1
A whereInstanceOf 0 4 1
A whereIfFunction 0 9 3
A whereIn 0 4 1
A where 0 11 5
A toObject 0 4 5

How to fix   Complexity   

Complexity

Complex classes like Collection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import * as Operators from './Collection/Where/Operators';
2
3
/**
4
 *
5
 */
6
export default class Collection extends Array {
7
8
    constructor(...items) {
9
        super(...items);
10
    }
11
12
    get operators() {
13
        return {
14
            '==': Operators.equal,
15
            '!=': Operators.notEqual,
16
            '>=': Operators.gtAndEqual,
17
            '<=': Operators.ltAndEqual,
18
            '>': Operators.gt,
19
            '<': Operators.lt,
20
        }
21
    }
22
23
    first() {
24
        return this[0] ?? null;
25
    }
26
27
    last() {
28
        return this.slice(-1)[0] ?? null;
29
    }
30
31
    merge(array): Collection {
32
        this.push(...array);
33
        return this;
34
    }
35
36
    pluck(field: string, keyField = '') {
37
        const lookUpFields = field.split('.');
38
39
        if (keyField) {
40
            const lookUpKeyField = keyField.split('.');
41
            const result = {};
42
            for (const i in this) {
43
                result[this._getRowFieldResult(this[i], lookUpKeyField)] = this._getRowFieldResult(this[i], lookUpFields);
44
            }
45
            return result;
46
        }
47
48
        const result = [];
49
        for (const i in this) {
50
            result.push(this._getRowFieldResult(this[i], lookUpFields));
51
        }
52
53
        return result;
54
    }
55
56
    random() {
57
        return this[Math.round(((this.length - 1) * Math.random()))];
58
    }
59
60
    toJSON() {
61
        return this.toObject();
62
    }
63
64
    toObject() {
65
        return this.map((item) => {
66
            return (item?.toObject?.() ?? item);
67
        });
68
    }
69
70
    unique(field: string): Collection {
71
        const unique = {};
72
        for (const i in this) {
73
            unique[this[i][field]] = this[i];
74
        }
75
76
        return new Collection(...Object.values(unique));
77
    }
78
79
    where(field: string, operator: string, value = null): Collection {
80
        value = value ?? operator;
81
        operator = (operator === value) ? '==' : operator;
82
83
        if (!Object.prototype.hasOwnProperty.call(this.operators, operator)) {
84
            throw new Error("Invalid comparison operator used");
85
        }
86
87
        return this.whereIfFunction(field, (field, object) => {
88
            return this.operators[operator](object[field], value);
89
        })
90
    }
91
92
    whereBetween(field: string, values): Collection {
93
        return this.whereIfFunction(field, (field, object) => {
94
            const fieldValue = object[field];
95
            return fieldValue >= values[0] && fieldValue <= values[1]
96
        });
97
    }
98
99
    whereIfFunction(field: string, whereIfFunction: CallableFunction): Collection {
100
        const register = new Collection();
101
        for (const i in this) {
102
            if (whereIfFunction(field, this[i])) {
103
                register.push(this[i]);
104
            }
105
        }
106
        return register;
107
    }
108
109
    whereIn(field: string, values): Collection {
110
        return this.whereIfFunction(field, (field, object) => {
111
            return values.includes(object[field]);
112
        });
113
    }
114
115
    whereInstanceOf(classInstance): Collection {
116
        return this.whereIfFunction(null, (field, object) => {
117
            return object instanceof classInstance;
118
        });
119
    }
120
121
    whereNotBetween(field: string, values): Collection {
122
        return this.whereIfFunction(field, (field, object) => {
123
            const fieldValue = object[field];
124
            return !(fieldValue >= values[0] && fieldValue <= values[1])
125
        });
126
    }
127
128
    whereNotIn(field: string, values): Collection {
129
        return this.whereIfFunction(field, (field, object) => {
130
            return !values.includes(object[field]);
131
        });
132
    }
133
134
    whereNotInstanceOf(classInstance): Collection {
135
        return this.whereIfFunction(null, (field, object) => {
136
            return !(object instanceof classInstance);
137
        });
138
    }
139
140
    whereNotNull(field: string): Collection {
141
        return this.whereIfFunction(field, (field, object) => {
142
            return object[field] !== null;
143
        });
144
    }
145
146
147
    whereNull(field: string): Collection {
148
        return this.whereIfFunction(field, (field, object) => {
149
            return object[field] === null;
150
        });
151
    }
152
153
154
155
156
157
    private _getRowFieldResult(row, lookUpFields) {
158
        let resultField = row[lookUpFields[0]] ?? null;
159
        for (let i = 1; i < lookUpFields.length; i++) {
160
            const currentField = lookUpFields[i];
161
162
            if (resultField === null) {
163
                break;
164
            }
165
166
            if (resultField instanceof Collection) {
167
                return resultField.pluck(lookUpFields[i]);
168
            }
169
170
            resultField = resultField[currentField] ?? null;
171
        }
172
173
        return resultField;
174
    }
175
}